use std::thread;
use std::sync::mpsc;
use std::sync::Arc;
use std::sync::Mutex;


///工作线程
struct Worker {
    id: usize,
    thread: Option<thread::JoinHandle<()>>,
}

impl Worker {
    ///创建工作线程,
    /// id:
    /// receiver:任务接收者，从通道中接收任务
    ///Arc 使得多个 worker 拥有接收端，而 Mutex 则确保一次只有一
    ///个 worker 能从接收端得到任务
    fn new(id: usize, receiver: Arc<Mutex<mpsc::Receiver<Message>>>) -> Worker {
        let thread = thread::spawn(move||{
            loop {
                //从通道中接收任务
                let job = receiver.lock().unwrap().recv().unwrap();
                println!("Worker{} got a job;", id);
                match job {
                    Message::NewJob(j) =>j(),
                    Message::Terminate => {break}, //跳出循环
                }
            }
            println!("Worker {} stop!", id);
        });
        Worker{
            id,
            thread: Some(thread),
        }
    }
}
///线程任务
type Job = Box<dyn FnOnce() + Send + 'static>; //参考thread::spawn的参数

///通道发送任务的枚举
enum Message {
    NewJob(Job), //发送任务
    Terminate, //发送关闭线程任务的消息
}

///线程池
pub struct ThreadPool {
    workers: Vec<Worker>,
    //通道发送者,发送任务
    sender: mpsc::Sender<Message>,
}

impl ThreadPool {
    pub fn new(size: usize) -> ThreadPool {
        assert!(size > 0);
        //创建通道
        let (sender, receiver):(mpsc::Sender<Message>, mpsc::Receiver<Message>) = mpsc::channel();
        //原子引用计数（多线程）,互斥量做同步,Arc 使得多个 worker 拥有接收端，而 Mutex 则确保一次只有一个 worker 能从接收端得到任务
        let receiver: Arc<Mutex<mpsc::Receiver<Message>>> = Arc::new(Mutex::new(receiver));
        //创建vec，指定大小
        let mut workers = Vec::with_capacity(size);

        for id in 0..size {
            //创建工作线程
            workers.push(Worker::new(id, Arc::clone(&receiver)));
        }

        ThreadPool {
            workers,
            sender,
        }
    }
    ///执行
    pub fn execute(&self, job: Job)

    {
        self.sender.send(Message::NewJob(job)).unwrap();
    }
}

///实现drop 优雅的停止线程任务
impl Drop for ThreadPool {
    fn drop(&mut self) {

        //发送关闭线程的通知
        for _ in &mut self.workers {
            self.sender.send(Message::Terminate).unwrap();
        }

        for worker in &mut self.workers {
            println!("Shutting down worker {}", worker.id);
            // take 将 thread 移动
            // 出 worker
            if let Some(thread) = worker.thread.take() {
                thread.join().unwrap(); //等待线程执行完
            }
        }
    }
}